﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.WindowsAzure.StorageClient;
using AzureGames.Model;
using AzureGames.Model.Statistics;

using AutoMapper;
using AzureGames.Data.Implementation.ServiceEntities;

namespace AzureGames.Data.Implementation
{
    public class UserStatisticsRepository : AzureTableRepository<UserStatisticsEntity>, IUserStatisticsRepository
    {
        const string PARTITIONKEY = "UserStatistics";

       public UserStatisticsRepository() : base("UserStatistics") {
           AutoMapper.Mapper.CreateMap<Model.Statistics.UserStatistics, ServiceEntities.UserStatisticsEntity>()
                  .ForMember(m => m.PartitionKey, s => s.UseValue(PARTITIONKEY))
                  .ForMember(m => m.RowKey, s => s.MapFrom(g => BuildKey(g.GameDefinitionID, g.CreatedDate, g.GameType, g.PlayerID)));

           AutoMapper.Mapper.CreateMap<ServiceEntities.UserStatisticsEntity, Model.Statistics.UserStatistics>();
       }


        public void AddUserStatistic(int gameDefinitionID, Model.Statistics.GameType gameType, DateTime date, string playerID, int state)
        {
            var current = Get(PARTITIONKEY, BuildKey(gameDefinitionID, date, gameType, playerID));

            if (current == null)
                Add(new UserStatisticsEntity
                    {
                        CancelledGames = state == Board.Cancelled ? 1 : 0,
                        CompletedGames = state == Board.Completed ? 1 : 0,
                        CreatedGames = state == Board.Created ? 1 : 0,
                        Date = date.Date,
                        CreatedDate = DateTime.Now,
                        GameDefinitionID = gameDefinitionID,
                        GameType = (int)gameType,
                        PlayerID = playerID,
                        PartitionKey = PARTITIONKEY,
                        RowKey = BuildKey(gameDefinitionID, date, gameType, playerID)
                    });
            else
            {
                switch (state)
                {
                    case Board.Completed:
                        current.CompletedGames += 1;
                        break;
                    case Board.Created:
                        current.CreatedGames += 1;
                        break;
                    case Board.Cancelled:
                        current.CancelledGames += 1;
                        break;
                }

                Update(current);
            }

        }

        private string BuildKey(int gameDefinitionID, DateTime date, GameType gameType, string playerID)
        {
            return string.Format("{0}:{1}:{2}:{3}", playerID, gameDefinitionID, date.ToString("yyyyMMdd"), gameType);
        }        

        public List<Model.Statistics.UserStatistics> GetUserStatistics(int gameDefinitionID, string playerID, Model.Statistics.RANGE range)
        {
            DateTime fromDate = GetDateMaxRange(range);

            var stats = dataContext.CreateQuery<UserStatisticsEntity>(this.tableName)
                .Where(n => n.PartitionKey == PARTITIONKEY && n.PlayerID == playerID && n.GameDefinitionID == gameDefinitionID && n.Date >= fromDate);
            // TODO: figure out why the cast is failing for statistics and not other entities
            // .Cast<Model.Statistics.UserStatistics>().ToList();
            
            List<UserStatistics> userStats =new List<UserStatistics>();
            
            foreach(var entity in stats)
                userStats.Add(entity);

            return userStats;
        }

        private DateTime GetDateMaxRange(RANGE range)
        {
            switch (range)
            {
                default:
                case RANGE.Today:
                    return DateTime.Now.Date;
                case RANGE.ThisWeek:
                    return DateTime.Now.Date.AddDays(-7);
                case RANGE.ThisYear:
                    return DateTime.Now.Date.AddYears(-1);
                case RANGE.ThisMonth:
                    return DateTime.Now.Date.AddMonths(-1);
            }
        }


        
        public void RemoveUserStatistic(int gameDefinitionID, GameType gameType, DateTime date, string playerID, int state)
        {
            var current = Get(PARTITIONKEY, BuildKey(gameDefinitionID, date, gameType, playerID));

            if (current == null)
                Add(new UserStatisticsEntity
                    {
                        CancelledGames = 0,
                        CompletedGames = 0,
                        CreatedGames = 0,
                        Date = date.Date,
                        GameDefinitionID = gameDefinitionID,
                        CreatedDate = DateTime.Now,
                        GameType = (int)gameType,
                        PlayerID = playerID,
                        PartitionKey = PARTITIONKEY,
                        RowKey = BuildKey(gameDefinitionID, date, gameType, playerID)
                    });
            else
            {
                switch (state)
                {
                    case Board.Completed:
                        current.CompletedGames -= 1;
                        break;
                    case Board.Created:
                        current.CreatedGames -= 1;
                        break;
                    case Board.Cancelled:
                        current.CancelledGames -= 1;
                        break;
                }

                Update(current);
     
            }
        }
    }
}
